#include "i2c_comm_isr.h"
#include "stm32f10x_rcc.h"
#include "stdio.h"
#include "stm32f10x_i2c.h"

/******* specified by user ************/
//#define I2C_REMAP
//#define SLAVE_10BIT_ADDRESS

/******* specify by user ************/

#define Transmitter             0x00
#define Receiver                0x01
static vu8 Direction = Transmitter;
static u16 SlaveADDR;
static u32 TxLength, RxLength;

static u32 DeviceOffset = 0xffffffff;

static u8 *pTxBuffer1;
static u8 *pTxBuffer2;
static u8 *pRxBuffer1;
static u8 *pRxBuffer2;
static uint8_t check_begin = 0;
vu8 MasterReceptionComplete = 0;
vu8 MasterTransitionComplete = 0; // to indicat master's send process
vu8 SlaveReceptionComplete = 0;
vu8 SlaveTransitionComplete = 0;

vu8 WriteComplete = 0; // to indicat target's internal write process

/*P-V operation on I2C1 or I2C2*/
vu8 PV_flag_1;
vu8 PV_flag_2;

I2C_STATE i2c_comm_state;


void  I2C_Comm_Init(I2C_TypeDef *I2Cx, u32 I2C_Speed, u16 I2C_Addr)
{
    /******* GPIO configuration and clock enable *********/
    GPIO_InitTypeDef  GPIO_InitStructure;
    I2C_InitTypeDef  I2C_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;


    if(I2Cx == I2C1)
    {
#ifdef I2C_REMAP
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9;
#else
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
#endif
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    }
    else if (I2Cx == I2C2)
    {
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    }

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /*********** I2C periphral configuration **********/
    I2C_DeInit(I2Cx);
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // fixed
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  // fixed
    I2C_InitStructure.I2C_OwnAddress1 = I2C_Addr;  // user parameter
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // fixed
#ifdef SLAVE_10BIT_ADDRESS
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_10bit;  // user define
#else
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
#endif
    I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; // user parameter
    //I2C_Cmd(I2Cx, ENABLE);
    I2C_Init(I2Cx, &I2C_InitStructure);
    I2C_Cmd(I2Cx, ENABLE);
    /************** I2C NVIC configuration *************************/
    /* 2 bit for pre-emption priority, 2 bits for subpriority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    if(I2Cx == I2C1)
    {
        NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
    }
    else
    {
        NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
    }
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    if(I2Cx == I2C1)
    {
        NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
    }
    else
    {
        NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
    }
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}



/*******************************************************************************
* Function Name  : I2C_Comm_MasterWrite
* Description    : write a block of data to slave devices.
* Input          : - I2Cx : the I2C port from which mcu send data out.
*                  - slave_addr : target slave
*                  - offset : the internal memory of target slave to place data
*                     if special value : no internal memory space of slave
*                  - pBuffer : pointer to the data ready to send
*                  - length : number of bytes to send.
* Output         : None
* Return         : None
*******************************************************************************/
void  I2C_Comm_MasterWrite(I2C_TypeDef *I2Cx, u16 slave_addr, u32 offset, u8 *pBuffer, u32 length)
{
    /* PV operation */
    if (I2Cx == I2C1)
    {
        if (PV_flag_1 != 0)
            return;
        PV_flag_1 |= 1;
        if (PV_flag_1 != 1)
            return;
        PV_flag_1 = 3;
    }
    else
    {
        if (PV_flag_2 != 0)
            return;
        PV_flag_2 |= 1;
        if (PV_flag_2 != 1)
            return;
        PV_flag_2 = 3;
    }
    /* enter rountine safely */

    /*initialize static parameter*/
    Direction = Transmitter;
    MasterTransitionComplete = 0;

    /*initialize static parameter according to input parameter*/
    SlaveADDR = slave_addr;//0x10;
    TxLength = length;
    DeviceOffset = offset;
    if (I2Cx == I2C1)
        pTxBuffer1 = pBuffer;
    else
        pTxBuffer2 = pBuffer;

    /* global state variable i2c_comm_state */
    i2c_comm_state = COMM_PRE;

    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
    /* Send START condition */
    if(I2C1->CR1 & 0x200)
        I2C1->CR1 &= 0xFDFF;
    I2C_GenerateSTART(I2Cx, ENABLE);
}


/*******************************************************************************
* Function Name  : I2C_Comm_MasterRead
* Description    : read a block of data from slave devices.
* Input          : - I2Cx : the I2C port from which mcu send data out.
*                  - slave_addr : target slave
*                  - offset : the internal memory of target slave to place data
*                     if special value : no internal memory space of slave
*                  - pBuffer : pointer to the data ready to send
*                  - length : number of bytes to send.
* Output         : None
* Return         : None
*******************************************************************************/
void  I2C_Comm_MasterRead(I2C_TypeDef *I2Cx, u16 slave_addr, u32 offset, u8 *pBuffer, u32 length)
{
    /* PV operation */
    if (I2Cx == I2C1)
    {
        if (PV_flag_1 != 0)
            return;
        PV_flag_1 |= 1;
        if (PV_flag_1 != 1)
            return;
        PV_flag_1 = 3;
    }
    else
    {
        if (PV_flag_2 != 0)
            return;
        PV_flag_2 |= 1;
        if (PV_flag_2 != 1)
            return;
        PV_flag_2 = 3;
    }
    /* enter rountine safely */

    /*initialize static parameter*/
    Direction = Receiver;
    MasterReceptionComplete = 0;

    /*initialize static parameter according to input parameter*/
    SlaveADDR = slave_addr;
    RxLength = length;
    DeviceOffset = offset;
    if (I2Cx == I2C1)
        pRxBuffer1 = pBuffer;
    else
        pRxBuffer2 = pBuffer;

    /* global state variable i2c_comm_state */
    i2c_comm_state = COMM_PRE;

    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_ERR , ENABLE);//only SB int allowed
    /* Send START condition */
    if(I2C1->CR1 & 0x200)
        I2C1->CR1 &= 0xFDFF;
    I2C_GenerateSTART(I2Cx, ENABLE);
}

/*******************************************************************************
* Function Name  : I2C_Comm_SlaveRead
* Description    : receive a block of data from the master.
* Input          : - I2Cx : the I2C port from which mcu read data in.
*                  - pBuffer : ram's location to locate the received data
*                  - length : number of bytes to receive.
* Output         : None
* Return         : None
*******************************************************************************/
void  I2C_Comm_SlaveRead(I2C_TypeDef *I2Cx, u8 *pBuffer, u32 length)
{
    /* PV operation */
    if (I2Cx == I2C1)
    {
        if (PV_flag_1 != 0)
            return;
        PV_flag_1 |= 1;
        if (PV_flag_1 != 1)
            return;
        PV_flag_1 = 3;
    }
    else
    {
        if (PV_flag_2 != 0)
            return;
        PV_flag_2 |= 1;
        if (PV_flag_2 != 1)
            return;
        PV_flag_2 = 3;
    }
    /* enter rountine safely */

    SlaveReceptionComplete = 0;

    RxLength = length;
    if (I2Cx == I2C1)
        pRxBuffer1 = pBuffer;
    else
        pRxBuffer2 = pBuffer;

    /* global state variable i2c_comm_state */
    i2c_comm_state = COMM_PRE;

    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_ERR , ENABLE); // ADDR BTF only
}

/*******************************************************************************
* Function Name  : I2C_Comm_SlaveWrite
* Description    : send a block of data out to the master.
* Input          : - I2Cx : the I2C port from which mcu send data out.
*                  - pBuffer : ram's location to locate the data to be send
*                  - length : number of bytes to receive.
* Output         : None
* Return         : None
*******************************************************************************/
void  I2C_Comm_SlaveWrite(I2C_TypeDef *I2Cx, u8 *pBuffer, u32 length)
{
    /* PV operation */
    if (I2Cx == I2C1)
    {
        if (PV_flag_1 != 0)
            return;
        PV_flag_1 |= 1;
        if (PV_flag_1 != 1)
            return;
        PV_flag_1 = 3;
    }
    else
    {
        if (PV_flag_2 != 0)
            return;
        PV_flag_2 |= 1;
        if (PV_flag_2 != 1)
            return;
        PV_flag_2 = 3;
    }
    /* enter rountine safely */

    SlaveTransitionComplete = 0;

    TxLength = length;
    if (I2Cx == I2C1)
        pTxBuffer1 = pBuffer;
    else
        pTxBuffer2 = pBuffer;

    /* global state variable i2c_comm_state */
    i2c_comm_state = COMM_PRE;

    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_ERR, ENABLE); // ADDR BTF only
}



void i2c1_evt_isr()
{
    //	 u32 ret;
    //	 ret = I2C_GetLastEvent(I2C1);
    //	 printf("\r\nret = 0x%x",ret);

    switch (I2C_GetLastEvent(I2C1))
    {
    /************************** Master Invoke**************************************/
    case I2C_EVENT_MASTER_MODE_SELECT:        /* EV5 */
        // MSL SB BUSY 30001
        if(!check_begin)
            i2c_comm_state = COMM_IN_PROCESS;

        if (Direction == Receiver)
        {
            if (DeviceOffset != 0xffffffff)
                I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Transmitter);
            else
                /* Send slave Address for read */
                I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Receiver);
        }
        else
        {
            /* Send slave Address for write */
            I2C_Send7bitAddress(I2C1, SlaveADDR, I2C_Direction_Transmitter);
        }
        I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE);//also TxE int allowed
        break;

    /********************** Master Receiver events ********************************/
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:  /* EV6 */
        // MSL BUSY ADDR 0x30002
        if (RxLength == 1)
        {
            /* Disable I2C1 acknowledgement */
            I2C_AcknowledgeConfig(I2C1, DISABLE);
            /* Send I2C1 STOP Condition */
            I2C_GenerateSTOP(I2C1, ENABLE);
        }
        break;

    case I2C_EVENT_MASTER_BYTE_RECEIVED:    /* EV7 */
        // MSL BUSY RXNE 0x30040
        /* Store I2C1 received data */
        *pRxBuffer1++ = I2C_ReceiveData (I2C1);
        RxLength--;
        /* Disable ACK and send I2C1 STOP condition before receiving the last data */
        if (RxLength == 1)
        {
            /* Disable I2C1 acknowledgement */
            I2C_AcknowledgeConfig(I2C1, DISABLE);
            /* Send I2C1 STOP Condition */
            I2C_GenerateSTOP(I2C1, ENABLE);
        }

        if (RxLength == 0)
        {
            MasterReceptionComplete = 1;
            i2c_comm_state = COMM_DONE;
            PV_flag_1 = 0;
        }
        break;



    /************************* Master Transmitter events **************************/
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:     /* EV8 just after EV6 */
        //BUSY, MSL, ADDR, TXE and TRA 0x70082
        if (check_begin)
        {
            check_begin = 0;
            WriteComplete = 1;
            i2c_comm_state = COMM_DONE;
            I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
            I2C_GenerateSTOP(I2C1, ENABLE);
            PV_flag_1 = 0;
            break;
        }

        if (DeviceOffset != 0xffffffff)
            I2C_SendData(I2C1, DeviceOffset);
        else
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
        }
        break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTING:       /* EV8 */
        //TRA, BUSY, MSL, TXE 0x70080
        if (Direction == Receiver)
        {
            DeviceOffset = 0xffffffff; // enter read-phase 2 (the same as no memory space)
            I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);
            while ((I2C1->CR1 & 0x200) == 0x200);
            I2C_GenerateSTART(I2C1, ENABLE);
            break;
        }

        if (TxLength > 0)
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
        }
        /* Disable the I2C_IT_BUF interrupt after sending the last buffer data
        (last EV8) to no allow a new interrupt with TxE and only BTF could generate it */
        else if(TxLength == 0)
        {
            I2C_ITConfig(I2C1,  I2C_IT_BUF, DISABLE);
            I2C_GenerateSTOP(I2C1, ENABLE);
        }
        break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:       /* EV8-2 */
        //TRA, BUSY, MSL, TXE and BTF 0x70084
        if (Direction == Transmitter)
        {
            MasterTransitionComplete = 1;
            I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
            // enable AF and SB and ADDR interrupt
            I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
            check_begin = 1;
            i2c_comm_state = CHECK_IN_PROCESS;
            //while ((I2C1->CR1 & 0x200) == 0x200);
            if(I2C1->CR1 & 0x200)
                I2C1->CR1 &= 0xFDFF;
            I2C_GenerateSTART(I2C1, ENABLE);
            break;
        }
        else
        {
            break;
        }
    /********************** Slave Transmitter Events ******************************/
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:  /* EV1 */
        //TRA, BUSY, TXE and ADDR 0x60082
        //printf("\r\ninterrupt\r\n");
        i2c_comm_state = COMM_IN_PROCESS;

        I2C_SendData(I2C1, *pTxBuffer1++);
        TxLength--;
        I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE); // also allow TxE
        break;

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:          /* EV3 */
        //TRA, BUSY, TXE and BTF  0x60084
        if (TxLength > 0)
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
        }
        break;

    case 0x60080:
        // TRA, BUSY,TXE, no BTF
        // if this case added, above case would never be reached
        if (TxLength > 0)
        {
            I2C_SendData(I2C1, *pTxBuffer1++);
            TxLength--;
            if (TxLength == 0)
            {
                SlaveTransitionComplete = 1;
                i2c_comm_state = COMM_DONE;
                I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);//close TxE int
                I2C_ITConfig(I2C1, I2C_IT_ERR , ENABLE);//to handle AF from master receiver
                PV_flag_1 = 0;
            }
        }

        break;

    /************************ Slave Receiver Events *******************************/
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:         /* EV1 */
        // BUSY ADDR 0x20002
        i2c_comm_state = COMM_IN_PROCESS;

        I2C_ITConfig(I2C1, I2C_IT_BUF , ENABLE); // also allow RxNE
        break;

    case I2C_EVENT_SLAVE_BYTE_RECEIVED:              /* EV2 */
        // BUSY RxNE 0x20040
        *pRxBuffer1++ = I2C_ReceiveData(I2C1);
        RxLength--; // controled by i2c1 sender

        if (RxLength == 0)
        {
            SlaveReceptionComplete = 1;
            I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE); // only EVT(STOPF) int
            I2C_ITConfig(I2C1, I2C_IT_EVT , ENABLE);
        }
        break;


    case I2C_EVENT_SLAVE_STOP_DETECTED:             /* EV4 */
        // STOPF 0x10
        /* Clear I2C2 STOPF flag: read of I2C_SR1 followed by a write in I2C_CR1 */
        (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        i2c_comm_state = COMM_DONE;
        PV_flag_1 = 0;
        //I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
        break;
    case 0x20050:
        // used when Rx and Tx handley by one mcu at the same time
        // receive last data and clear stopf
        *pRxBuffer1++ = I2C_ReceiveData(I2C1);
        RxLength--;
        SlaveReceptionComplete = 1;

        (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
        I2C_ITConfig(I2C1, I2C_IT_BUF , DISABLE);
        break;

    case 0x20010:
        // busy+stopf
        // when last data read isr exist, there would be stopf flag
        //which is set during read ISR. and as sender's check begin
        // busy also set
        i2c_comm_state = CHECK_IN_PROCESS;
        (void)(I2C_GetITStatus(I2C1, I2C_IT_STOPF));
        I2C_Cmd(I2C1, ENABLE);
        break;

    /******************************* default Events *******************************/
    default:
        break;
    }
}

void i2c1_err_isr()
{

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF))
    {
        if (check_begin)
            I2C_GenerateSTART(I2C1, ENABLE);
        else if (I2C1->SR2 & 0x01)
        {
            I2C_GenerateSTOP(I2C1, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_1 = 0;
        }

        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    }

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR))
    {
        if (I2C1->SR2 & 0x01)
        {
            I2C_GenerateSTOP(I2C1, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_1 = 0;
        }

        I2C_ClearFlag(I2C1, I2C_FLAG_BERR);
    }
}


void i2c2_evt_isr()
{

    //		uint32_t ret_1;
    //		ret_1 = I2C_GetLastEvent(I2C2);
    //		printf("\r\nret_1 = 0x%x\r\n",ret_1);

    switch (I2C_GetLastEvent(I2C2))
    {
    /************************** Master Invoke**************************************/
    case I2C_EVENT_MASTER_MODE_SELECT:        /* EV5 */
        // MSL SB BUSY 30001
        if(!check_begin)
            i2c_comm_state = COMM_IN_PROCESS;

        if (Direction == Receiver)
        {
            if (DeviceOffset != 0xffffffff)
                I2C_Send7bitAddress(I2C2, SlaveADDR, I2C_Direction_Transmitter);
            else
                /* Send slave Address for read */
                I2C_Send7bitAddress(I2C2, SlaveADDR, I2C_Direction_Receiver);
        }
        else
        {
            /* Send slave Address for write */
            I2C_Send7bitAddress(I2C2, SlaveADDR, I2C_Direction_Transmitter);
        }
        I2C_ITConfig(I2C2, I2C_IT_BUF , ENABLE);//also TxE int allowed
        break;

    /********************** Master Receiver events ********************************/
    case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:  /* EV6 */
        // MSL BUSY ADDR 0x30002
        if (RxLength == 1)
        {
            /* Disable I2C1 acknowledgement */
            I2C_AcknowledgeConfig(I2C2, DISABLE);
            /* Send I2C1 STOP Condition */
            I2C_GenerateSTOP(I2C2, ENABLE);
        }
        break;

    case I2C_EVENT_MASTER_BYTE_RECEIVED:    /* EV7 */
        // MSL BUSY RXNE 0x30040
        /* Store I2C1 received data */
        *pRxBuffer2++ = I2C_ReceiveData (I2C2);
        RxLength--;
        /* Disable ACK and send I2C1 STOP condition before receiving the last data */
        if (RxLength == 1)
        {
            /* Disable I2C1 acknowledgement */
            I2C_AcknowledgeConfig(I2C2, DISABLE);
            /* Send I2C1 STOP Condition */
            I2C_GenerateSTOP(I2C2, ENABLE);
        }

        if (RxLength == 0)
        {
            MasterReceptionComplete = 1;
            i2c_comm_state = COMM_DONE;
            PV_flag_2 = 0;
        }
        break;



    /************************* Master Transmitter events **************************/
    case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:     /* EV8 just after EV6 */
        //BUSY, MSL, ADDR, TXE and TRA 0x70082
        if (check_begin)
        {
            check_begin = 0;
            WriteComplete = 1;
            i2c_comm_state = COMM_DONE;
            I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
            I2C_GenerateSTOP(I2C2, ENABLE);
            PV_flag_2 = 0;
            break;
        }

        if (DeviceOffset != 0xffffffff)
            I2C_SendData(I2C2, DeviceOffset);
        else
        {
            I2C_SendData(I2C2, *pTxBuffer2++);
            TxLength--;
        }
        break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTING:       /* EV8 */
        //TRA, BUSY, MSL, TXE 0x70080
        if (Direction == Receiver)
        {
            DeviceOffset = 0xffffffff; // enter read-phase 2 (the same as no memory space)
            I2C_ITConfig(I2C2, I2C_IT_BUF , DISABLE);
            while ((I2C2->CR1 & 0x200) == 0x200);
            I2C_GenerateSTART(I2C2, ENABLE);
            break;
        }

        if (TxLength > 0)
        {
            I2C_SendData(I2C2, *pTxBuffer2++);
            TxLength--;
        }
        /* Disable the I2C_IT_BUF interrupt after sending the last buffer data
        (last EV8) to no allow a new interrupt with TxE and only BTF could generate it */
        else if(TxLength == 0)
        {
            I2C_ITConfig(I2C2,  I2C_IT_BUF, DISABLE);
            I2C_GenerateSTOP(I2C2, ENABLE);
        }
        break;

    case I2C_EVENT_MASTER_BYTE_TRANSMITTED:       /* EV8-2 */
        //TRA, BUSY, MSL, TXE and BTF 0x70084
        if (Direction == Transmitter)
        {
            MasterTransitionComplete = 1;
            I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
            // enable AF and SB and ADDR interrupt
            I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
            check_begin = 1;
            i2c_comm_state = CHECK_IN_PROCESS;
            //while ((I2C1->CR1 & 0x200) == 0x200);
            if(I2C2->CR1 & 0x200)
                I2C2->CR1 &= 0xFDFF;
            I2C_GenerateSTART(I2C2, ENABLE);
            break;
        }
        else
        {
            break;
        }
    /********************** Slave Transmitter Events ******************************/
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:  /* EV1 */
        //TRA, BUSY, TXE and ADDR 0x60082
        i2c_comm_state = COMM_IN_PROCESS;

        I2C_SendData(I2C2, *pTxBuffer2++);
        TxLength--;
        I2C_ITConfig(I2C2, I2C_IT_BUF , ENABLE); // also allow TxE
        break;

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:          /* EV3 */
        //TRA, BUSY, TXE and BTF  0x60084
        if (TxLength > 0)
        {
            I2C_SendData(I2C2, *pTxBuffer2++);
            TxLength--;
        }
        break;

    case 0x60080:
        // TRA, BUSY,TXE, no BTF
        // if this case added, above case would never be reached
        if (TxLength > 0)
        {
            I2C_SendData(I2C2, *pTxBuffer2++);
            TxLength--;
            if (TxLength == 0)
            {
                SlaveTransitionComplete = 1;
                i2c_comm_state = COMM_DONE;
                I2C_ITConfig(I2C2, I2C_IT_BUF , DISABLE);//close TxE int
                I2C_ITConfig(I2C2, I2C_IT_ERR , ENABLE);//to handle AF from master receiver
                PV_flag_2 = 0;
            }
        }

        break;

    /************************ Slave Receiver Events *******************************/
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:         /* EV1 */
        // BUSY ADDR 0x20002
        i2c_comm_state = COMM_IN_PROCESS;

        I2C_ITConfig(I2C2, I2C_IT_BUF , ENABLE); // also allow RxNE
        break;

    case I2C_EVENT_SLAVE_BYTE_RECEIVED:              /* EV2 */
        // BUSY RxNE 0x20040
        *pRxBuffer2++ = I2C_ReceiveData(I2C2);
        RxLength--; // controled by i2c1 sender
        if (RxLength == 0)
        {
            SlaveReceptionComplete = 1;
            I2C_ITConfig(I2C2, I2C_IT_BUF , DISABLE); // only EVT(STOPF) int
            I2C_ITConfig(I2C2, I2C_IT_EVT , ENABLE);
        }
        break;


    case I2C_EVENT_SLAVE_STOP_DETECTED:             /* EV4 */
        // STOPF 0x10
        /* Clear I2C2 STOPF flag: read of I2C_SR1 followed by a write in I2C_CR1 */
        (void)(I2C_GetITStatus(I2C2, I2C_IT_STOPF));
        I2C_Cmd(I2C2, ENABLE);
        i2c_comm_state = COMM_DONE;
        PV_flag_2 = 0;
        //I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
        break;
    case 0x20050:
        // used when Rx and Tx handley by one mcu at the same time
        // receive last data and clear stopf
        // BUSY+RxNE+STOP
        *pRxBuffer2++ = I2C_ReceiveData(I2C2);
        RxLength--;
        SlaveReceptionComplete = 1;

        (void)(I2C_GetITStatus(I2C2, I2C_IT_STOPF));
        I2C_Cmd(I2C2, ENABLE);
        I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
        I2C_ITConfig(I2C2, I2C_IT_BUF , DISABLE);
        break;

    case 0x20010:
        // busy+stopf
        // when last data read isr exist, there would be stopf flag
        //which is set during read ISR. and as sender's check begin
        // busy also set
        i2c_comm_state = CHECK_IN_PROCESS;
        (void)(I2C_GetITStatus(I2C2, I2C_IT_STOPF));
        I2C_Cmd(I2C2, ENABLE);
        break;

    default:
        break;
    }
}

void i2c2_err_isr()
{
    if (I2C_GetFlagStatus(I2C2, I2C_FLAG_AF))
    {
        if (check_begin)
            I2C_GenerateSTART(I2C2, ENABLE);
        else if (I2C2->SR2 & 0x01)
        {
            // only in master mode, can send stop to finish
            I2C_GenerateSTOP(I2C2, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_2 = 0;
        }

        I2C_ClearFlag(I2C2, I2C_FLAG_AF);
    }

    if (I2C_GetFlagStatus(I2C2, I2C_FLAG_BERR))
    {
        if (I2C2->SR1 & 0x01)
        {
            I2C_GenerateSTOP(I2C2, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_2 = 0;
        }

        I2C_ClearFlag(I2C2, I2C_FLAG_BERR);
    }
}
